package ETL

import (
	"context"
	"database/sql"
	"fmt"
	"db2s/go-log/log"
	"db2s/ref"
	"reflect"
	"runtime"
)

func beginTrx(db *sql.DB) (trx *sql.Tx, err error) {
	defer func() {
		if err1 := recover(); err1 != nil {
			stack := make([]byte, 4096)
			length := runtime.Stack(stack, true)
			fmt.Printf("异常位置:%v \n%s\n ----", db, stack[:length])
		}
	}()
	if trx, err = db.Begin(); err != nil {
		return
	}
	return
}

// trxCommit 事务提交
func trxCommit(begin *sql.Tx) error {
	var err error
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(fmt.Sprintf("trxCommit Recovered from panic: %v", r))
		}
	}()
	if err = begin.Commit(); err != nil {
		err = fmt.Errorf(fmt.Sprintf("%v", err))
		if err1 := begin.Rollback(); err1 != nil {
			err = fmt.Errorf(fmt.Sprintf("%v %v", err, err1))
		}
		return err
	}
	return nil
}
func setSessionVariables(ctx context.Context, trx *sql.Tx, strSql string) (err error) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println(fmt.Sprintf("setSessionVariables Recovered from panic: %v", r))
		}
	}()
	if ctx != nil {
		if _, err = trx.ExecContext(ctx, strSql); err != nil {
			err = fmt.Errorf(fmt.Sprintf("Failed to conn  to database error is %v", err))
			if err1 := trx.Rollback(); err1 != nil {
				err = fmt.Errorf(fmt.Sprintf("%v trx rollback fail. error is %v", err, err1))
			}
			return err
		}
	} else {
		if _, err = trx.Exec(strSql); err != nil {
			err = fmt.Errorf(fmt.Sprintf("Failed to execl sql to database error is %v", err))
			if err1 := trx.Rollback(); err1 != nil {
				err = fmt.Errorf(fmt.Sprintf("%v trx rollback fail. error is %v", err, err1))
			}
			return err
		}
	}
	return nil
}
func rowsClose(SqlRows *sql.Rows) (err error) {
	var event = "[rowsClose]"
	if err = SqlRows.Close(); err != nil {
		err = ref.ErrAddPrintf(event, fmt.Errorf(fmt.Sprintf("DB rows close fail. %v", err)))
		return
	}
	return
}

func retriesExecSql(fn func(sessionOptions []string, setVariables any) (result FnReturn), options []string, ary any) FnReturn {
	var (
		maxRetries     = 1
		fnReturnResult FnReturn
	)
	defer func() {
		if r := ref.RecoverPanic("RetriesExecSql", recover()); fnReturnResult.Err == nil && r != nil {
			fnReturnResult.Err = r
		}
	}()
	for attempts := 0; attempts < maxRetries; attempts++ {
		fnReturnResult = fn(options, ary)
		if fnReturnResult.Err != nil {
			return fnReturnResult
		}
	}
	return fnReturnResult
}
func getBaseExecSql(setVariables any) (res []string) {
	var event = "[getBaseExecSql]"
	switch setVariables.(type) {
	case string:
		return []string{setVariables.(string)}
	case *string:
		return []string{*setVariables.(*string)}
	case []string:
		return setVariables.([]string)
	case []*string:
		for _, v := range setVariables.([]*string) {
			var oo = *v
			res = append(res, oo)
			ref.SetFinalizer(v)
		}
		return
	default:
		log.ErrorLog().Error(event, fmt.Errorf(fmt.Sprintf("not metch type. curry type %v", reflect.TypeOf(setVariables).String())))
		return
	}
}
func baseExecSql(conn *sql.Conn, object string) (timeout int64, err error) {
	var res sql.Result
	if res, err = conn.ExecContext(context.Background(), object); err != nil {
		err = fmt.Errorf(fmt.Sprintf("exec sql is %v error info is %v", object, err))
		return
	}
	return res.RowsAffected()
}
func setConnectionSessionVariables(conn *sql.Conn, sessionOptions []string) (err error) {
	if len(sessionOptions) == 0 {
		return
	}
	for _, v := range sessionOptions {
		if _, err = conn.ExecContext(context.TODO(), v); err != nil {
			return
		}
	}
	return
}
